#include "httpclient.h"
#include <curl/curl.h>
#include <QDebug>
#include <QByteArray>
#include <QtConcurrent>
#include <qmetatype.h>

void HttpClient::OnOperateFinished()
{
    if(auto watcher = (QFutureWatcher<DefHttpResult>*)(sender());watcher)
    {
        auto result = watcher->result();
        if(watcher == m_get_watcher)
            emit signal_get_finished(result);
        else if(watcher == m_post_watcher)
            emit signal_post_finished(result);
    }
}

HttpClient::HttpClient(QObject *parent)
    : QObject(parent), m_timeout(30), m_userAgent("Qt-Curl-HTTP-Client/1.0")
{
    qRegisterMetaType<DefHttpResult>("DefHttpResult");
    curl_global_init(CURL_GLOBAL_DEFAULT);
    if(nullptr == m_get_watcher)
        m_get_watcher = new QFutureWatcher<DefHttpResult>(this);
    if(nullptr == m_post_watcher)
        m_post_watcher = new QFutureWatcher<DefHttpResult>(this);
    connect(m_get_watcher,&QFutureWatcher<DefHttpResult>::finished,this,&HttpClient::OnOperateFinished);
    connect(m_post_watcher,&QFutureWatcher<DefHttpResult>::finished,this,&HttpClient::OnOperateFinished);
}

HttpClient::~HttpClient()
{
    curl_global_cleanup();
}

size_t HttpClient::writeCallback(void* contents, size_t size, size_t nmemb, void* userp)
{
    size_t realsize = size * nmemb;
    QByteArray *response{};
    response = static_cast<QByteArray*>(userp);
    response->append(static_cast<char*>(contents), realsize);
    return realsize;
}

DefHttpResult HttpClient::httpGet(const QString& url)
{
    DefHttpResult result{};
    CURL* curl = curl_easy_init();
    if (!curl) {
        QString error{"Failed to initialize CURL"};
        qDebug() << error;
        result.status_code=-1;
        result.error = error;
        return result;
    }

    QByteArray responseData;

    // 设置 CURL 选项
    curl_easy_setopt(curl, CURLOPT_URL, url.toUtf8().constData());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseData);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, m_timeout);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, m_userAgent.toUtf8().constData());

    // 禁用 SSL 验证
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);    // 不验证对等证书
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);    // 不验证主机名

    // 跟随重定向
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    int http_code{};

    // 执行请求
    CURLcode res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
        qDebug() << "curl_easy_perform() failed:" << curl_easy_strerror(res);
        result.error = QString::fromLatin1(curl_easy_strerror(res));
        result.status_code = http_code;
    } else {
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
        qDebug() << "HTTP GET Response code:" << http_code;
        result.response = QString::fromUtf8(responseData);
        result.status_code = http_code;
    }
    curl_easy_cleanup(curl);
    return result;
}

DefHttpResult HttpClient::httpPost(const QString& url, const QByteArray& postData)
{
    DefHttpResult result{};
    CURL* curl = curl_easy_init();
    if (!curl) {
        QString error{"Failed to initialize CURL"};
        qDebug() << error;
        result.status_code = -1;
        result.error = error;
        return result;
    }

    QByteArray responseData{};

    // 设置 CURL 选项
    curl_easy_setopt(curl, CURLOPT_URL, url.toUtf8().constData());
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.constData());
    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postData.size());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseData);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, m_timeout);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, m_userAgent.toUtf8().constData());

    // 禁用 SSL 验证
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);    // 不验证对等证书
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);    // 不验证主机名

    // 设置 Content-Type
    struct curl_slist* headers = nullptr;
    headers = curl_slist_append(headers, "Content-Type: application/json");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

   int http_code{};
    // 执行请求
    CURLcode res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
        qDebug() << "curl_easy_perform() failed:" << curl_easy_strerror(res);
        result.error = QString::fromLatin1(curl_easy_strerror(res));
        result.status_code = http_code;
    } else {
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
        qDebug() << "HTTP POST Response code:" << http_code;
        result.response = QString::fromUtf8(responseData);
        result.status_code = http_code;
    }

    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    return result;
}

void HttpClient::setTimeout(long timeout)
{
    m_timeout = timeout;
}

void HttpClient::setUserAgent(const QString& userAgent)
{
    m_userAgent = userAgent;
}

void HttpClient::HttpGetAsync(const QString &url)
{

    auto future =  QtConcurrent::run([this,url]()->DefHttpResult{
        return this->httpGet(url);
    });
    m_get_watcher->setFuture(future);
}

void HttpClient::HttpPostAsync(const QString &url, const QByteArray &post_data)
{
    auto future = QtConcurrent::run([this,url,post_data]()->DefHttpResult{
        return this->httpPost(url,post_data);
    });
    m_post_watcher->setFuture(future);
}
